/**
 * @Author: easten
 * @Created: 2024-07-26 01:16:03
 * @Description: 设备数据监测
 *
 */
import { ApiDevice, ApiFacility, ApiPoint, ApiRealtime } from "_common/api/iot";
import {
  IotDeviceData,
  ModuleCommonProps,
  TreeDataModel,
} from "_common/DataType";
import { IotPoint } from "_common/entity";
import classNames from "classnames";
import DeviceCard from "components/DeviceCard";
import React, { useEffect, useMemo, useRef, useState } from "react";
import {
  Alert,
  Button,
  Card,
  Cascader,
  Col,
  Divider,
  MessagePlugin,
  NotificationPlugin,
  PrimaryTableCol,
  Radio,
  Row,
  Space,
  Switch,
  Table,
} from "tdesign-react";
import DetailDrawer from "./DetailDrawer";
import { TagItem } from "components";
import { ProductCode } from "_common/enum";
import { iotDataService } from "_common/service";
import dayjs from "dayjs";
import GreaseTable from "./grease/GreaseTable";
import DesignerViewer from "designer/view2";
import { DesignerInstance } from "designer/view2/DesignerViewer";
import { useSize } from "ahooks";
import { setDeviceDataCache } from "utils/StorageUtil";
export type IotMonitorCompProps = ModuleCommonProps & {
  column?: number; // 卡片模式下每一行显示多少个
  height?: number;
  /**
   * 监控模式：卡片视图、表格视图、图形视图、加脂机模式
   */
  viewType?: ("card" | "table" | "graphic" | "grease")[];
  defaultType?: string;
};
const viewTypeMap: any = {
  card: "卡片模式",
  table: "表格模式",
  graphic: "图形模式",
  grease: "表格模式",
};
type PointDataType = IotPoint & IotDeviceData & {};
const IotMonitorComp: React.FC<IotMonitorCompProps> = (
  props: IotMonitorCompProps
) => {
  const { axios, className, height, viewType, defaultType } = props;
  const [facilityTree, setFacilityTree] = useState<TreeDataModel[]>([]);
  // 选中的车间id
  const [facilityId, setFacilityId] = useState<number>();
  const [visible, setVisible] = useState<boolean>(false);
  // 获取测点列表
  const [points, setPoints] = useState<IotPoint[]>([]);
  const [selected, setSelected] = useState<IotPoint>();
  const [dataList, setDataList] = useState<PointDataType[]>([]);
  // 定义实时数据
  const [realtimeData, setRealtimeData] = useState<IotDeviceData>();
  // 设计图
  const [mode, setMode] = useState<string>();
  const [modeList, setModeList] = useState<string[]>([]);
  const [deviceType, setDeviceType] = useState<number>(0);
  const apiFacility = new ApiFacility(axios);
  const apiPoint = new ApiPoint(axios);
  const apiRealtime = new ApiRealtime(axios);
  const apiDevice = new ApiDevice(axios);
  const rootRef = useRef<HTMLDivElement>(null);
  // const viewRef = useRef<DesignerViewInstance>(null);
  const viewRef = React.useRef<DesignerInstance>(null);
  const pointsRef = useRef<IotPoint[]>([]);
  const size = useSize(rootRef);

  let notification = useRef<any>();

  useEffect(() => {
    // 订阅实时数据
    let sub = iotDataService.iot.subscribe((data) => {
      updateGraphic(data);
      updateTable(data);
      setRealtimeData(data);
    });
    return () => {
      sub.unsubscribe();
    };
  }, []);

  useEffect(() => {
    if (!viewType) {
      // 默认模式
      setModeList(["graphic", "table"]);
      setMode("graphic");
    } else {
      setModeList(viewType);
      setMode(viewType[0]);
    }
  }, [viewType]);

  // 获取设施列表
  useEffect(() => {
    getFacilities();
    apiDevice.getDeviceList().then((res) => {
      if (res && res.code == 200 && res.data) {
        setDeviceDataCache(res.data);
      }
    });
  }, []);

  // 获取设施树
  const getFacilities = async () => {
    const response = await apiFacility.getTree();
    if (response && response.code == 200 && response.data) {
      setFacilityTree(response.data);
      // 默认选中第一个车间
      setFacilityId(response.data[0]?.children[0]?.value);
    }
  };

  // 获取设施配置
  const getDesignerJson = async () => {
    const response = await apiFacility.getDesignJson(facilityId!);
    if (response && response.code == 200 && response.data) {
      viewRef.current?.load(response.data);
    } else {
      viewRef.current?.destroy();
      MessagePlugin.warning("该设施未找到设计图");
    }
  };

  // 获取监测点
  useEffect(() => {
    if (facilityId) {
      getPoints();
    }
  }, [facilityId]);

  // 获取监测点
  const getPoints = async () => {
    const response = await apiPoint.getList(facilityId!);
    if (response && response.code == 200 && response.data) {
      setPoints(response.data);
      pointsRef.current = response.data;
      setDataList(
        response.data?.filter(
          (item) => item.device?.dtCode == ProductCode.WD
        ) as []
      );
    }
  };

  useEffect(() => {
    if (mode == "graphic" || mode == "table") {
      getRealtime();
    }
  }, [mode, facilityId]);

  // 获取实时数据
  const getRealtime = async () => {
    const response = await apiRealtime.getAll();
    if (response && response.code == 200 && response.data) {
      // 更新组件
      const _time = setTimeout(() => {
        response.data?.forEach((a) => {
          if (mode == "graphic") {
            updateGraphic(a);
          } else if (mode == "table") {
            updateTable(a);
          }
        });
        clearTimeout(_time);
      }, 1000);
    }
  };

  // 更新图形组件
  const updateGraphic = (data: IotDeviceData) => {
    viewRef.current?.updateData?.(data);
  };

  // 更新表格数据
  const updateTable = (data: IotDeviceData) => {
    setDataList((pre) =>
      pre.map((item) =>
        item.deviceCode === data.deviceCode ? { ...item, ...data } : item
      )
    );
  };

  // 卡片内容
  const cardNode = useMemo(() => {
    let _data = points;
    if (deviceType != 0) {
      _data = points.filter((item) => item.device?.dtCode == deviceType);
    }
    return (
      <Card style={{ minHeight: "calc(100vh - 205px)", overflowX: "hidden" }}>
        <Row gutter={[16, 12]}>
          {_data.map((item) => {
            return (
              <Col key={item.id} span={3} lg={3} md={6} sm={12} xs={12} xxl={3}>
                <DeviceCard
                  point={item}
                  onSelect={(point) => {
                    // 查看详情
                    setVisible(true);
                    setSelected(point);
                  }}
                />
              </Col>
            );
          })}
        </Row>
      </Card>
    );
  }, [points, deviceType]);

  // 表格定义
  const columns: PrimaryTableCol<PointDataType>[] = [
    {
      align: "left",
      width: 120,
      ellipsis: true,
      colKey: "orderNo",
      title: "序号",
      cell: ({ rowIndex }) => {
        return rowIndex + 1;
      },
    },
    {
      align: "left",
      ellipsis: true,
      colKey: "code",
      title: "测点编码",
      cell: ({ row }) => {
        return (
          <Button
            tag="a"
            variant="text"
            size="small"
            theme="primary"
            onClick={() => {
              setVisible(true);
              setSelected(row);
            }}
          >
            {row.code}
          </Button>
        );
      },
    },
    {
      align: "left",
      ellipsis: true,
      colKey: "name",
      title: "测点名称",
    },
    {
      align: "left",
      ellipsis: true,
      colKey: "location",
      title: "测点位置",
    },
    {
      align: "center",
      ellipsis: true,
      colKey: "deviceCode",
      title: "设备ID",
    },
    {
      align: "center",
      ellipsis: true,
      colKey: "value1",
      title: "温度 ℃",
      cell: ({ row }) => {
        return <>{row.value1}</>;
      },
    },
    {
      align: "center",
      ellipsis: true,
      colKey: "value2",
      title: "电压 v",
      cell: ({ row }) => {
        return <>{row.value2}</>;
      },
    },
    {
      align: "center",
      ellipsis: true,
      colKey: "time",
      title: "监测时间",
      cell: ({ row }) => {
        return row.time ? dayjs(row.time).format("YYYY-MM-DD HH:mm:ss") : "--";
      },
    },
  ];
  const tableNode = useMemo(() => {
    return (
      <>
        <Alert
          message="温馨提示：表格模式只显示无线温度数据"
          theme="warning"
          close
        />
        <Table<IotPoint>
          bordered
          data={dataList}
          columns={columns}
          rowKey="id"
          verticalAlign="middle"
          hover
          maxHeight={height ?? 700}
          scroll={{
            type: "lazy",
          }}
        />
      </>
    );
  }, [points, deviceType, dataList]);

  useEffect(() => {
    const tim = setTimeout(() => {
      if (viewRef.current && facilityId) {
        getDesignerJson();
      }
    }, 100);
    if (mode != "graphic") {
      viewRef.current?.destroy();
      console.log("notification:", notification.current);
      notification.current && NotificationPlugin.close(notification.current);
    }
    return () => {
      clearTimeout(tim);
    };
  }, [facilityId, mode]);

  const sizeData = useMemo(() => {
    if (!size)
      return {
        width: 1920,
        height: 1080,
      };
    return {
      width: size.width,
      height: height ?? 800,
    };
  }, [size, height]);

  const openNotification = () => {
    let _notification = (notification.current = NotificationPlugin.info({
      title: "操作提示",
      content: (
        <div className="flex flex-col">
          <span>按【Alt】+ 【鼠标滚轮】对视图进行放大缩小</span>
          <span>按【鼠标右键】对视图进行拖动</span>
          <span className="text-red-700">拖动到合适范围后请锁定视图</span>
        </div>
      ),
      placement: "top-right",
      closeBtn: true,
      duration: 0,
      offset: [-10, 10],
      onCloseBtnClick: () => {
        NotificationPlugin.close(_notification);
      },
    }));
  };

  return (
    <div className={classNames(className, "h-full")} ref={rootRef}>
      <Card bordered={false} className="mb-2 shadow-xl">
        <div className=" flex flex-row w-full items-center gap-2">
          <div className="w-1/4">
            <Cascader
              style={{ width: "100%" }}
              lazy
              options={facilityTree}
              filterable
              label="设施选择："
              clearable
              value={facilityId}
              onChange={(value, context) => {
                if (value && context.node) {
                  if (
                    context.node.data.type == 1 &&
                    (!context.node.data.children ||
                      (context.node.data.children as []).length == 0)
                  ) {
                    // todo 清除查询
                    MessagePlugin.warning("该站点下未添加车间", 1000);
                  } else {
                    setFacilityId(value as number);
                  }
                } else {
                  setFacilityId(undefined);
                }
              }}
            />
          </div>
          <Divider layout="vertical" className="h-8" />
          <Radio.Group
            size="small"
            defaultValue={defaultType}
            onChange={(v) => setMode(v as string)}
          >
            {/* <Radio.Button value="graphic">图形模式</Radio.Button>
            <Radio.Button value="table">表格模式</Radio.Button>
            <Radio.Button value="card">卡片模式</Radio.Button> */}
            {modeList.map((a, b) => {
              return (
                <Radio.Button value={a} key={b}>
                  {viewTypeMap[a]}
                </Radio.Button>
              );
            })}
          </Radio.Group>
          <Divider layout="vertical" className="h-8" />
          {mode == "card" ? (
            <Radio.Group
              defaultValue={0}
              size="small"
              onChange={(v) => setDeviceType(v as number)}
            >
              <Radio.Button value={0}>全部</Radio.Button>
              <Radio.Button value={116}>温度</Radio.Button>
              <Radio.Button value={112}>温湿度</Radio.Button>
              <Radio.Button value={111}>烟感</Radio.Button>
              <Radio.Button value={114}>水浸</Radio.Button>
            </Radio.Group>
          ) : null}
          <TagItem
            label="设备总数"
            value={points.length}
            tagColor="green"
            outline
          />
          {/* <TagItem label="在线设备" value={12} tagColor="success" outline /> */}
          {/* <TagItem label="异常设备" value={12} tagColor="red" outline /> */}
          <Button
            theme="primary"
            className="ml-4"
            size="small"
            variant="outline"
            onClick={() => {
              getFacilities();
            }}
          >
            刷新数据
          </Button>

          {mode == "graphic" && (
            <Space>
              {/* <Button
                theme="primary"
                className="ml-4"
                size="small"
                variant="outline"
                onClick={() => {
                  viewRef.current?.setLayout?.("123");
                }}
              >
                重置画布
              </Button> */}
              <Switch
                label="锁定视图"
                defaultValue={true}
                onChange={(e) => {
                  viewRef.current?.setLayout?.(e);
                  if (!e) {
                    openNotification();
                  }
                }}
              />
            </Space>
          )}
        </div>
      </Card>
      {mode == "card" && cardNode}
      {mode == "table" && tableNode}
      {mode == "grease" && (
        <GreaseTable
          dataList={pointsRef.current}
          height={height}
          facilityId={facilityId}
          axios={axios}
          realData={realtimeData}
          onSelect={(row) => {
            setVisible(true);
            setSelected(row);
          }}
        />
      )}
      {mode == "graphic" && (
        <DesignerViewer
          ref={viewRef}
          width={sizeData.width}
          height={sizeData.height}
          onClick={(deviceCode) => {
            if (deviceCode) {
              let point = pointsRef.current?.find(
                (item) => item.deviceCode == Number(deviceCode)
              );
              if (point) {
                setSelected(point);
                setVisible(true);
              } else {
                MessagePlugin.warning("未找到该设备", 1000);
              }
            }
          }}
        />
      )}
      <DetailDrawer
        axios={axios}
        open={visible}
        onClose={setVisible}
        point={selected}
        height={sizeData.height}
      />
    </div>
  );
};
export default IotMonitorComp;

{
  /* <IotDesignerViewer
          ref={viewRef}
          width={sizeData.width}
          height={sizeData.height}
          onClick={(deviceCode) => {
            if (deviceCode) {
              let point = pointsRef.current?.find(
                (item) => item.deviceCode == Number(deviceCode)
              );
              setSelected(point);
              setVisible(true);
            }
          }}
        /> */
}
